import type * as Koa from 'koa';
import axios from 'axios';

import config from '../config/index';
import HttpHelper from '../utils/HttpHelper';
import { ProxyPaths } from '../services/proxy/index';

const defaultAuthConfig = {
  eShield: {
    accountId: '1',
    regionId: '84',
  },
};

const responseUnauthorized = (response: Koa.Response) => {
  response.status = 401;
  response.body = 'SSO token is invalid';
};

export default async (context: Koa.Context, next: Koa.Next) => {
  const { request, response } = context;
  /**
   * 仅直接请求业务服务器的 api 需要通过独立 SSO 验证身份。
   * 其中 SSO Server 使用 http header token 验证身份，不需要额外执行 /sso/verify 检查
   */
  const needRequestVerify = request.path.startsWith(ProxyPaths.StandaloneBackend)
    && !request.path.startsWith(ProxyPaths.StandalonePlatformSso);
  if (!needRequestVerify) {
    await next();
    return;
  }
  const requestToken = HttpHelper.filedMixedToSingular(request.headers.token);
  if (!requestToken) {
    responseUnauthorized(response);
    return;
  }
  const verifyResponse = await axios.get(
    `${config.standalone.platformSso}/sso/verify`,
    { headers: { token: requestToken } },
  );
  if (verifyResponse.data.code !== '200 OK' || !verifyResponse.data.data) {
    responseUnauthorized(response);
    return;
  }
  /**
   * 当 token 在 SSO Server 的过期时间为 5 分钟。过期后 30 分钟内，使用过期 token 发起请求，
   * SSO Server 会在 response header 里返回新的 token 以供继续连续使用。
   *
   * GET /sso/verify 接口同样会被这一机制影响，所以若通过 GET /sso/verify 发现 token 需要刷新，
   * 则会将 token 放到原业务请求的 response header 里。
   *
   * 前端发现 response header 携带 token 时，应当及时刷新浏览器本地的 token 缓存。
   */
  const refreshedToken = verifyResponse.headers.token;
  if (refreshedToken) {
    response.set('token', verifyResponse.headers.token);
  }
  request.headers.userId = verifyResponse.data.data;
  request.headers.accountId = defaultAuthConfig.eShield.accountId;
  request.headers.regionId = defaultAuthConfig.eShield.regionId;
  await next();
};
